package net.markos.action;

import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;

import net.markos.gen.EntityA;
import net.markos.gen.EntityB;
import net.markos.gen.EntityC;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.AnnotationConfiguration;

public class MainClass {

	public static final int SIZE = 3;

	public static void main(String[] args) {
		SessionFactory sessionFactory = new AnnotationConfiguration()
				.configure().buildSessionFactory();

		// First unit of work
		Session session = sessionFactory.openSession();

		Transaction tx = session.beginTransaction();
		tx.begin();
		for (int i = 0; i < SIZE; i++) {

			EntityA a = new EntityA();
			a.setName("name a-" + i);
			List<EntityB> bList = new ArrayList<EntityB>();
			for (int k = 0; k < SIZE; k++) {

				EntityB b = new EntityB();
				b.setName("name b-" + i + k);
				b.setEntityA(a);
				List<EntityC> cList = new ArrayList<EntityC>();
				for (int l = 0; l < SIZE; l++) {
					EntityC c = new EntityC();
					c.setName("name c-" + i + k + l);
					c.setEntityB(b);
					cList.add(c);
				}
				b.setEntityCs(cList);

				bList.add(b);
			}
			a.setEntityBs(bList);

			session.save(a);

			for (EntityB b : a.getEntityBs()) {
				session.save(b);
				for (EntityC c : b.getEntityCs()) {
					session.save(c);
				}
			}
		}

		tx.commit();
		session.close();

		// Second unit of work
		Session newSession = sessionFactory.openSession();
		Transaction newTransaction = newSession.beginTransaction();

		// Criteria crit = newSession.createCriteria(EntityA.class).createAlias(
		// "entityBs", "b", Criteria.LEFT_JOIN).createAlias("b.entityCs",
		// "c", Criteria.LEFT_JOIN).addOrder(Order.desc("name")).addOrder(
		// Order.desc("b.name")).addOrder(Order.desc("c.name"))
		// .setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
		// List<EntityA> alist = crit.list();

		List<Object[]> olist = newSession
				.createSQLQuery(
						"select {a.*}, {b.*}, {c.*} from ENTITY_A a left outer join ENTITY_B b on a.ID=b.ENTITY_A_ID left outer join ENTITY_C c on b.ID=c.ENTITY_B_ID order by a.NAME desc, b.NAME asc, c.NAME asc")
				.addEntity("a", EntityA.class).addJoin("b", "a.entityBs")
				.addJoin("c", "b.entityCs").list();

		EntityA tempA;
		List<EntityA> al = new ArrayList<EntityA>();

		for (Object[] obArr : olist) {
			tempA = (EntityA) obArr[0];

			if (!al.contains(tempA)) {
				al.add(tempA);
				LinkedHashSet<EntityB> noDupBs = new LinkedHashSet<EntityB>();
				noDupBs.addAll(tempA.getEntityBs());
				tempA.setEntityBs(new ArrayList<EntityB>(noDupBs));

				for (EntityB tempB : tempA.getEntityBs()) {
					LinkedHashSet<EntityC> noDupCs = new LinkedHashSet<EntityC>();
					noDupCs.addAll(tempB.getEntityCs());
					tempB.setEntityCs(new ArrayList<EntityC>(noDupCs));
				}
			}
		}

		System.out.println(al.size());

		for (EntityA a : al) {
			for (EntityB b : a.getEntityBs()) {
				for (EntityC c : b.getEntityCs()) {
					System.out.println(c);
				}
			}
		}
	}
}
